using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using EventFlowLibrary.Player;
using System.Collections.Generic;
using EventFlowLibrary;
using EventFlowLibrary.LevelComponents;

namespace ScreenManagement
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields



        float pauseAlpha;

        /// <summary>
        /// The world for the game.
        /// </summary>
        World world;

        /// <summary>
        /// How long since the game has been started till this screen has been loaded.
        /// </summary>
        double startTime;

        /// <summary>
        /// Variables for loading a level.
        /// </summary>
        LoadVariables loadVariables;

        /// <summary>
        /// Game settings set by the user
        /// </summary>
        GameSettings gameSettings;
        
        #endregion

        #region Properties


        /// <summary>
        /// The logic for deciding whether the game is paused depends on whether
        /// this is a networked or single player game. If we are in a network session,
        /// we should go on updating the game even when the user tabs away from us or
        /// brings up the pause menu, because even though the local player is not
        /// responding to input, other remote players may not be paused. In single
        /// player modes, however, we want everything to pause if the game loses focus.
        /// </summary>
        new bool IsActive
        {
            get
            {
                // Pause behavior for single player games.
                return base.IsActive;
            }
        }


        #endregion

        #region Initialization

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="_startTime">Total seconds since starting the game.</param>
        /// <param name="_loadVariables"></param>
        public GameplayScreen(double _startTime, LoadVariables _loadVariables, GameSettings _gameSettings)
        {
            // Track our variables
            loadVariables = _loadVariables;
            gameSettings = _gameSettings;
            startTime = _startTime;

            TransitionOnTime = TimeSpan.FromSeconds(1.0);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }


        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            // Create the world
            world = new World(this.ScreenManager.Game, startTime, loadVariables, gameSettings);
            this.ScreenManager.Game.Components.Add(world);

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            ScreenManager.Game.ResetElapsedTime();
        }


        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            base.UnloadContent();

            if (world != null)
            {
                world.Dispose();
                world = null;
            }
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the state of the game.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            if (IsActive && world != null)
            {
                world.Update(gameTime);
            }
        }


        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(GameTime _gameTime, InputState _input)
        {
            if (_input == null)
                throw new ArgumentNullException("input");

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !_input.CurrentGamePadStates[(int)this.ControllingPlayer].IsConnected &&
                                       _input.GamePadWasConnected[(int)this.ControllingPlayer];

            if (_input.IsPauseGame(this.ControllingPlayer) || gamePadDisconnected)
            {
                ScreenManager.AddScreen(new PauseMenuScreen(this.world), this.ControllingPlayer);
                return;
            }

            world.HandleInput(_gameTime, _input);
        }



        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            // This game has a blue background. Why? Because!
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.Black, 0, 0);

            // Have to draw seperately so that pause draws OVER the game play
            if (world != null)
                world.Draw(gameTime);

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }

        #endregion
    }
}
